package com.diamondparking.action;

import com.diamondparking.model.Claim;
import com.diamondparking.model.Color;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import org.apache.commons.lang.StringUtils;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.framework.EntityController;

@Stateful
@Name("searcher")
@Scope(ScopeType.SESSION)
public class SearchBean extends EntityController implements Search {

    private boolean dirty;
    private List<Claim> results;
    private Long claimId;
    private String claimCustomer;
    private String claimCarWash;
    private Date from;
    private Date to;
    private String locationStall;
    private String parkedByUsername;
    private String licensePlateNumber;
    private Color color;
    private String makeName;

    public SearchBean() {
        results = new ArrayList<Claim>();
    }

    public boolean isDirty() {
        return dirty;
    }

    public void setDirty() {
        dirty = true;
    }

    public void setClean() {
        dirty = false;
    }

    public Long getClaimId() {
        return claimId;
    }

    public void setClaimId(Long claimId) {
        this.claimId = claimId;
        setDirty();
    }

    public String getClaimCustomer() {
        return claimCustomer;
    }

    public void setClaimCustomer(String claimCustomer) {
        this.claimCustomer = claimCustomer;
        setDirty();
    }

    public String getClaimCarWash() {
        return claimCarWash;
    }

    public void setClaimCarWash(String claimCarWash) {
        this.claimCarWash = claimCarWash;
        setDirty();
    }

    public Date getFrom() {
        return from;
    }

    public void setFrom(Date from) {
        this.from = from;
        setDirty();
    }

    public Date getTo() {
        return to;
    }

    public void setTo(Date to) {
        this.to = to;
        setDirty();
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
        setDirty();
    }

    public String getLicensePlateNumber() {
        return licensePlateNumber;
    }

    public void setLicensePlateNumber(String licensePlateNumber) {
        this.licensePlateNumber = licensePlateNumber;
        setDirty();
    }

    public String getLocationStall() {
        return locationStall;
    }

    public void setLocationStall(String locationStall) {
        this.locationStall = locationStall;
        setDirty();
    }

    public String getMakeName() {
        return makeName;
    }

    public void setMakeName(String makeName) {
        this.makeName = makeName;
        setDirty();
    }

    public String getParkedByUsername() {
        return parkedByUsername;
    }

    public void setParkedByUsername(String parkedByUsername) {
        this.parkedByUsername = parkedByUsername;
        setDirty();
    }

    public List<Claim> getResults() {
        if (results == null || isDirty()) {
            initResults();
        }
        return results;
    }

    public void initResults() {
        if (!conditionsExist()) {
            results = Collections.EMPTY_LIST;
            return;
        }

        List<String> conditions = new ArrayList<String>();
        addConditions(conditions);
        String conditionsString = StringUtils.join(conditions, " and ");
        results = createQuery("SELECT c FROM Claim c WHERE " + conditionsString).getResultList();
        setClean();
    }

    public boolean claimIdExists() {
        return claimId != null;
    }

    public boolean customerExists() {
        return StringUtils.isNotBlank(claimCustomer);
    }

    public boolean carWashExists() {
        return StringUtils.isNotBlank(claimCarWash);
    }

    public boolean dateRangeExists() {
        return from != null && to != null;
    }

    public boolean partialDateRangeExists() {
        return from != null || to != null;
    }

    public boolean locationExists() {
        return StringUtils.isNotBlank(locationStall);
    }

    public boolean parkedByExists() {
        return StringUtils.isNotBlank(parkedByUsername);
    }

    public boolean makeExists() {
        return StringUtils.isNotBlank(makeName);
    }

    public boolean licenseNumberExists() {
        return StringUtils.isNotBlank(licensePlateNumber);
    }

    public boolean colorExists() {
        return color != null;
    }

    public boolean conditionsExist() {
        boolean result = claimIdExists();
        result |= customerExists();
        result |= carWashExists();
        result |= dateRangeExists();
        result |= locationExists();
        result |= parkedByExists();
        result |= makeExists();
        result |= licenseNumberExists();
        result |= colorExists();
        return result;
    }

    public void addConditions(List<String> conditions) {
        if (claimIdExists()) {
            addIdCondition(conditions);
        }

        if (customerExists()) {
            addCustomerCondition(conditions);
        }

        if (carWashExists()) {
            addCarWashCondition(conditions);
        }

        if (dateRangeExists()) {
            addDateCondition(conditions);
        } else if (partialDateRangeExists()) {
            getFacesMessages().addFromResourceBundle("com.diamondparking.DATERANGE_REQUIRED");
        }
        
        if (locationExists()) {
            addLocationCondition(conditions);
        }

        if (parkedByExists()) {
            addParkedByCondition(conditions);
        }
        
        if (makeExists()) {
            addMakeCondition(conditions);
        }
        
        if (licenseNumberExists()) {
            addLicenseNumberCondition(conditions);
        }
        
        if (colorExists()) {
            addColorCondition(conditions);
        }
    }

    public void addIdCondition(List<String> conditions) {
        String query = " c.id = %d ";
        conditions.add(String.format(query, claimId));
    }

    public void addCustomerCondition(List<String> conditions) {
        String query = " lower(c.customer) like lower('%s%%') ";
        conditions.add(String.format(query, claimCustomer));
    }

    public void addCarWashCondition(List<String> conditions) {
        String query = " c.carWash = %b ";
        conditions.add(String.format(query, claimCarWash.equals("Yes")));
    }

    public void addDateCondition(List<String> conditions) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String fromStr = sdf.format(from);
        String toStr = sdf.format(to);

        String query = " c.returned >= '%s' and c.returned <= '%s' ";
        conditions.add(String.format(query, fromStr, toStr));
    }

    public void addColorCondition(List<String> conditions) {
        String query = " c.car.color = %d ";
        conditions.add(String.format(query, color.ordinal()));
    }

    public void addLicenseNumberCondition(List<String> conditions) {
        String query = " lower(c.car.licensePlate) like lower('%%%s%%') ";
        conditions.add(String.format(query, licensePlateNumber));
    }

    public void addLocationCondition(List<String> conditions) {
        String query = " lower(c.location.stall) like lower('%%%s%%') ";
        conditions.add(String.format(query, locationStall));
    }

    public void addMakeCondition(List<String> conditions) {
        String query = " lower(c.car.make.name) like lower('%%%s%%') ";
        conditions.add(String.format(query, makeName));
    }

    public void addParkedByCondition(List<String> conditions) {
        String query = " lower(c.parkedBy.username) like lower('%%%s%%') ";
        conditions.add(String.format(query, parkedByUsername));
    }
    
    @Destroy
    @Remove
    public void destroy() {
    }
}
